﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using gts;

namespace GCard
{
    class GtsCard
    {
        class CardAxisStatus
        {
            /// <summary>
            /// 总状态
            /// </summary>
            private bool cardInitOk;        //初始化OK
            private bool allRunReady;       //回零完成，无报警、警告，运动准备就绪  
            private bool allIsWarning;      //轴有警告        
            private bool allIsAlarming;     //轴在报警
            private bool allIsRunning;      //轴在运动
            private bool allIsStopping;     //轴在停止
            private bool allIsEStopping;    //轴在急停 
            private bool allIsLimit;        //轴碰到限位
            private bool allNoServo;        //轴没有使能
            private bool allHomeOK;         //所有轴都回零完成

            /// <summary>
            /// 单轴状态
            /// </summary>
            private bool[] oneRunReady;       //回零完成，无报警、警告，运动准备就绪  
            private bool[] oneIsWarning;      //轴有警告        
            private bool[] oneIsAlarming;     //轴在报警
            private bool[] oneIsRunning;      //轴在运动
            private bool[] oneIsStopping;     //轴在停止
            private bool[] oneIsEStopping;    //轴在急停   
            private bool[] oneIsLimit;        //轴碰到限位
            private bool[] oneNoServo;        //轴没有使能
            private bool[] oneHomeOK;         //轴回零完成

            /// <summary>
            /// 
            /// </summary>
            public bool Crd1IsStop;     //坐标系1是停止的
            public bool Crd2IsStop;     //坐标系2是停止的

        }

        /// <summary>
        /// 轴状态类
        /// </summary>
        public class AxisStatus
        {
            public double prfPos_p, encPos_p, prfVel_p, encVel_p, prfAcc_p, encAcc_p, prfDec_p, encDec_p; //单位pluse
            public double prfPos_mm, encPos_mm, prfVel_mm, encVel_mm, prfAcc_mm, encAcc_mm, prfDec_mm, encDec_mm; //单位mm
            public bool axisServoOn, axisAlarm, axisLimitP, axisLimitN, axisRun, axisStop, axisEStop, axisHome;
            public AxisStatus()             //初始化参数
            {
                axisServoOn = axisAlarm = axisLimitP = axisLimitN = axisRun = axisStop = axisEStop = axisHome = false;
                prfPos_p = encPos_p = prfVel_p = encVel_p = prfAcc_p = encAcc_p = prfDec_p = encDec_p = 0.0;
                prfPos_mm = encPos_mm = prfVel_mm = encVel_mm = prfAcc_mm = encAcc_mm = prfDec_mm = encDec_mm = 0.0;
            }

            /// <summary>
            /// 当前轴停止判断(规划器停止判断)
            /// </summary>
            /// <param name="cardNo"></param>
            /// <param name="axisNo"></param>
            public bool AxisIsStop1(short cardNo, short axisNo)
            {
                short sRtn;
                int pSts = 0;
                uint pclock = 0;
                try
                {
                    sRtn = gts.mc.GT_GetSts(cardNo, axisNo, out pSts, 1, out pclock);
                    return ((pSts & 0x0400) == 0);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return false;
                }
            }

            /// <summary>
            /// 当前轴停止判断(到位信号判断)
            /// </summary>
            /// <param name="cardNo"></param>
            /// <param name="axisNo"></param>
            /// <param name="isNagation">电机到位信号是否取反</param>
            /// <returns></returns>
            public bool AxisIsStop2(short cardNo, short axisNo, bool isNagation)
            {
                int pValue = 0;
                short sRtn;
                try
                {
                    sRtn = gts.mc.GT_GetDi(cardNo, gts.mc.MC_ARRIVE, out pValue);
                    if (isNagation == false)
                    {
                        return ((pValue & (1 << (axisNo - 1))) == 0);
                    }
                    else
                    {
                        return ((pValue & (1 << (axisNo - 1))) != 0);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return false;
                }
            }

            /// <summary>
            /// 到位误差带判断(前提条件是设置了误差带)
            /// </summary>
            /// <param name="cardNo"></param>
            /// <param name="axisNo"></param>
            /// <param name="isNagation"></param>
            /// <returns></returns>
            public bool AxisIsStop3(short cardNo, short axisNo)
            {
                short sRtn;
                int psts = 0;
                uint pclock = 0;
                try
                {
                    sRtn = gts.mc.GT_GetSts(cardNo, axisNo, out psts, 1, out pclock);
                    return ((psts & 0x0800) != 0);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return false;
                }
            }

        }

        /// <summary>
        /// 电气输入输出信号状态类
        /// </summary>
        public class ElecIo
        {
            public double[] adc = new double[8];
            public bool[] input = new bool[16];
            public bool[] output = new bool[16];
            public bool[] alarm = new bool[8];
            public bool[] limitP = new bool[8];
            public bool[] limitN = new bool[8];
            public bool[] home = new bool[8];
            public bool[] servoOn = new bool[8];
            public bool[] reset = new bool[8];
        }

        //内部变量
        private short sRtn = 0;  //返回值
        private short cardNo;    //卡号
        private short cardNum;    //卡数
        private short axisNo;    //轴号
        private short axisNum;   //轴数
        private uint pClock;     //时钟信号单位1ms
        private short transfer;  //转换当量

        private CardAxisStatus cardStatus;  //卡状态
        private AxisStatus[] axisStatus;    //单轴状态
        
        //public void GtsCard(short cardNo, short axisNo)
        //{
            
        //}
        /// <summary>
        /// 工作轴使能
        /// </summary>
        /// <param name="cardNo">卡号</param>
        /// <param name="axisNum">上使能轴数</param>
        public void MCAxisOnAll(short cardNo ,short axisNum)
        {
            sRtn = gts.mc.GT_ClrSts(cardNo, 1, axisNum);
            for (short i = 0; i < axisNum; i++)
            {
                sRtn = gts.mc.GT_AxisOn(cardNo, (short)(i + 1));
            }
        }

        /// <summary>
        /// 工作轴下使能
        /// </summary>
        /// <param name="cardNo"></param>
        /// <param name="axisNum"></param>
        public void MCAxisOffAll(short cardNo, short axisNum)
        {
            for (short i = 0; i < axisNum; i++)
            {
                sRtn = gts.mc.GT_AxisOff(cardNo, (short)(i + 1));
            }
        }

        /// <summary>
        /// 初始化卡: 打开运动控制卡、复位、加载配置文件、清除报警
        /// </summary>
        /// <param name="_cardNo">卡号</param>
        /// <param name="str">配置文件名</param>
        /// <returns>指令是否执行成功</returns>
        public bool OpenCardInit(short cardNo, string str)
        {
            short sRtn = 0;
            sRtn += gts.mc.GT_Open(cardNo, 0, 1);
            sRtn += gts.mc.GT_Reset(cardNo);
            sRtn += gts.mc.GT_LoadConfig(cardNo, str);          //初始化配置
            sRtn += gts.mc.GT_ClrSts(cardNo, 1, axisNum);
            if (sRtn == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// JOG运动
        /// </summary>
        /// <param name="cardNo">卡号</param>
        /// <param name="axis">轴号</param>
        /// <param name="jogP">JOG运动参数</param>
        /// <param name="velJ">JOG运动速度</param>
        /// <returns></returns>
        public void JOG(short cardNo, short axis, gts.mc.TJogPrm jogP, double velJ)
        {
            short sRtn;
            gts.mc.TJogPrm pJog;

            sRtn = gts.mc.GT_PrfJog(cardNo, axis);
            pJog = jogP;
            //pJog.acc = jogP.acc;
            //pJog.dec = jogP.dec;
            //pJog.smooth = jogP.smooth//平滑系数,取值范围[0, 1),平滑系数的数值越大，加减速过程越平稳。

            gts.mc.GT_SetJogPrm(cardNo, axis, ref pJog);//设置jog运动参数
            gts.mc.GT_SetVel(cardNo, axis, velJ);//设置目标速度,velJd的符号决定JOG运动方向
            gts.mc.GT_Update(cardNo, 1 << (axis - 1));//更新轴运动

            //return sRtn;
        }

        /// <summary>
        /// 绝对位置点位运动
        /// </summary>
        /// <param name="cardNo">卡号</param>
        /// <param name="axis">轴号</param>
        /// <param name="velP">速度</param>
        /// <param name="acc">加速度</param>
        /// <param name="dec">减速度</param>
        /// <param name="posP">位置</param>
        /// <returns></returns>
        public void P2PAbs(short cardNo, short axis, double velP, double acc, double dec, int posP)  //单轴绝对位置点位运动
        {
            short sRtn;//返回值
            gts.mc.TTrapPrm trap;
            sRtn = gts.mc.GT_PrfTrap(cardNo, axis);     //设置为点位运动，模式切换需要停止轴运动。
            //若返回值为 1：若当前轴在规划运动，请调用GT_Stop停止运动再调用该指令。
            sRtn = gts.mc.GT_GetTrapPrm(cardNo, axis, out trap);       /*读取点位运动参数（不一定需要）。若返回值为 1：请检查当前轴是否为 Trap 模式
                                                                    若不是，请先调用 GT_PrfTrap 将当前轴设置为 Trap 模式。*/
            trap.acc = acc;              //单位pulse/ms2
            trap.dec = dec;              //单位pulse/ms2
            trap.velStart = 0;           //起跳速度，默认为0。
            trap.smoothTime = 0;         //平滑时间，使加减速更为平滑。范围[0,50]单位ms。

            sRtn = gts.mc.GT_SetTrapPrm(cardNo, axis, ref trap);//设置点位运动参数。

            sRtn = gts.mc.GT_SetVel(cardNo, axis, velP);        //设置目标速度
            sRtn = gts.mc.GT_SetPos(cardNo, axis, posP);        //设置目标位置
            sRtn = gts.mc.GT_Update(cardNo, 1 << (axis - 1));   //更新轴运动

            //return sRtn;        //返回值
        }

        public void P2PInc(short cardNo, short axis, double velP, double acc, double dec, int posP)  //单轴增量位置点位运动
        {
            short sRtn;     //返回值
            double prfPos; //规划脉冲
            uint pClock;    //时钟信号
            gts.mc.TTrapPrm trap;
            sRtn = gts.mc.GT_PrfTrap(cardNo, axis);     //设置为点位运动，模式切换需要停止轴运动。
            //若返回值为 1：若当前轴在规划运动，请调用GT_Stop停止运动再调用该指令。
            sRtn = gts.mc.GT_GetTrapPrm(cardNo, axis, out trap);       /*读取点位运动参数（不一定需要）。若返回值为 1：请检查当前轴是否为 Trap 模式
                                                                    若不是，请先调用 GT_PrfTrap 将当前轴设置为 Trap 模式。*/
            trap.acc = acc;              //单位pulse/ms2
            trap.dec = dec;              //单位pulse/ms2
            trap.velStart = 0;           //起跳速度，默认为0。
            trap.smoothTime = 0;         //平滑时间，使加减速更为平滑。范围[0,50]单位ms。

            sRtn = gts.mc.GT_SetTrapPrm(cardNo, axis, ref trap);//设置点位运动参数。
            sRtn = gts.mc.GT_GetPrfPos(cardNo, axis, out prfPos, 1, out pClock);//读取规划位置
            sRtn = gts.mc.GT_SetVel(cardNo, axis, velP);        //设置目标速度
            sRtn = gts.mc.GT_SetPos(cardNo, axis, (int)(posP + prfPos));        //设置目标位置
            sRtn = gts.mc.GT_Update(cardNo, 1 << (axis - 1));   //更新轴运动

            //return sRtn;        //返回值
        }
        /// <summary>
        /// 智能回原点（多种方式）
        /// </summary>
        /// <param name="_cardNo">卡号</param>
        /// <param name="_axis">轴号</param>
        /// <param name="homePrm">回零参数</param>
        /// <param name="pHomeStatus">回零状态</param>
        /// <returns></returns>
        public void  SmartHome(short cardNo, short axis, gts.mc.THomePrm homePrm, out gts.mc.THomeStatus pHomeStatus)
        {
            short sRtn;
            int pValue;
            gts.mc.THomePrm tHomePrm;
            gts.mc.TTrapPrm trapPrm;
            sRtn = gts.mc.GT_ClrSts(cardNum, axisNo, axisNum);
            sRtn = gts.mc.GT_ZeroPos(cardNo, axis, 1);

            sRtn = gts.mc.GT_GetDi(0, gts.mc.MC_HOME, out pValue);//以未取反home开关为例
            if (pValue == 0)                            //home开关触发，即当前位置在home点
            {
                sRtn = gts.mc.GT_PrfTrap(cardNo, axis);//设置点位模式
                sRtn = gts.mc.GT_GetTrapPrm(cardNo, axis, out trapPrm);//获取点位运动参数
                trapPrm.acc = 1;
                trapPrm.dec = 1;
                trapPrm.smoothTime = 30;
                sRtn = gts.mc.GT_SetTrapPrm(cardNo, axis, ref trapPrm);//设置点位参数
                sRtn = gts.mc.GT_SetVel(cardNo, axis, 50);//设置小段位移速度
                sRtn = gts.mc.GT_SetPos(cardNo, axis, 10000);//设置小段位移距离大于Home开关宽度。+-代表方向
                sRtn = gts.mc.GT_Update(cardNo, 1 << (axis - 1));//启动小段位移
            }
            //sRtn = gts.mc.GT_ZeroPos(cardNo, axis, 1);
            sRtn = gts.mc.GT_GetHomePrm(cardNo, axis, out tHomePrm);
            tHomePrm = homePrm;

            sRtn = gts.mc.GT_GoHome(cardNo, axis, ref tHomePrm);//启动SmartHome回原点
            do
            {
                sRtn = gts.mc.GT_GetHomeStatus(cardNo, axis, out pHomeStatus);//获取回原点状态
            } while (pHomeStatus.run == 1); // 等待搜索原点停止
            sRtn = gts.mc.GT_ZeroPos(cardNo, axis, 1);
        }

        /// <summary>
        /// 建立坐标系
        /// </summary>
        /// <param name="cardNo">卡号</param>
        /// <param name="crd">坐标系号1，2</param>
        /// <param name="dimension">坐标系维数</param>
        /// <param name="axisNo">坐标系各维度对应轴号</param>
        /// <param name="maxVel">坐标系最大合成速度</param>
        /// <param name="maxAcc">坐标系最大合成加速度</param>
        public void SetCoordinate(short cardNo,short crd,short dimension ,short[] axisNo,double maxVel,double maxAcc)
        {
            short sRtn = 0;
            short[] demin = new short[8];//表示1-8轴的数组
            for (short i = 0; i < axisNo.Length; i++)
            {
                demin[axisNo[i]] = (short)(i+1);//规划器与坐标系对应；
            }
            mc.TCrdPrm crdPrm = new mc.TCrdPrm();
            crdPrm.dimension = dimension;                        // 建立二维的坐标系
            crdPrm.synVelMax = maxVel;                      // 坐标系的最大合成速度是: 500 pulse/ms
            crdPrm.synAccMax = maxAcc;                        // 坐标系的最大合成加速度是: 2 pulse/ms^2
            crdPrm.evenTime = 0;                         // 坐标系的最小匀速时间为0
            crdPrm.profile1 = demin[0];                         // 规划器1对应到X轴                       
            crdPrm.profile2 = demin[1];                         // 规划器2对应到Y轴
            crdPrm.profile3 = demin[2];
            crdPrm.profile4 = demin[3];
            crdPrm.profile5 = demin[4];
            crdPrm.profile6 = demin[5];
            crdPrm.profile7 = demin[6];                         // 若profile7为1，规划器7对应到X轴           
            crdPrm.profile8 = demin[7];
            crdPrm.setOriginFlag = 1;                    // 需要设置加工坐标系原点位置
            crdPrm.originPos1 = 0;                       // 加工坐标系原点位置在(0,0)，即与机床坐标系原点重合
            crdPrm.originPos2 = 0;
            crdPrm.originPos3 = 0;
            crdPrm.originPos4 = 0;
            crdPrm.originPos5 = 0;
            crdPrm.originPos6 = 0;
            crdPrm.originPos7 = 0;
            crdPrm.originPos8 = 0;
            sRtn += gts.mc.GT_SetCrdPrm(cardNo, crd, ref crdPrm);   //必须在轴调用停止状态下,重建坐标系会清除原有数据
        }

        public void SendInterpolationData()
        {

        }
        #region
        /// <summary>
        /// 电子齿轮模式 需要开启主轴运动后从轴才会运动
        /// </summary>
        /// <param name="cardNo">卡号</param>
        /// <param name="axisM">主轴</param>
        /// <param name="axisS">从轴</param>
        /// <param name="gearDir">跟随方向 0双向,1正向,2负向</param>
        /// <param name="gearType">跟随类型 1编码器,2规划,3改变当量后轴规划或编码器</param>
        /// <param name="ratio">电子齿轮比 从/主</param>
        /// <param name="slope">离合区 不能小于0或=1</param>
        /// <returns></returns>      
        public int Gear(short cardNo, short axisM, short axisS, short gearDir, short gearType, int ratio, int slope)
        {
            short sRtn = 0;
            sRtn = gts.mc.GT_PrfGear(cardNo, axisS, gearDir);                  //从轴跟随模式
            sRtn = gts.mc.GT_SetGearMaster(cardNo, axisS, axisM, gearType, 0); //后两个参数选择跟随类型
            sRtn = gts.mc.GT_SetGearRatio(cardNo, axisS, 1, ratio, slope);     //slope不能小于0或=1
            sRtn = gts.mc.GT_GearStart(cardNo, 1 << (axisS - 1));
            return sRtn;
        }
        #endregion

        

        #region
        /// <summary>
        /// 读取IO信号
        /// </summary>
        /// <param name="cardNo">卡号</param>
        /// <param name="type">IO类型</param>
        /// <param name="iNo">IO号 0-15或0-7</param>
        /// <param name="iEverBit"></param>
        /// <returns></returns>
        public int ReadIO(short cardNo, short type, short iNo, out int iEverBit)
        {
            short sRtn;
            int iValue;

            if (iNo > 15) Console.WriteLine("IO在0-15位");
            sRtn = gts.mc.GT_GetDi(cardNo, type, out iValue);
            if ((1 << (iNo) & iValue) == 0)
            {
                iEverBit = 0;
            }
            else
            {
                iEverBit = 1;
            }
            return sRtn;
        }
        #endregion

        bool flag = true;//判断标志位
        /// <summary>
        /// 强制输出点
        /// </summary>
        public void Output(short DoType, short DoIndex)
        {
            if (flag == false)//判断标志位
            {
                mc.GT_SetDoBit(0, DoType, DoIndex, 0);
                flag = !flag;
            }
            else if (flag == true)
            {
                mc.GT_SetDoBit(0, DoType, DoIndex, 1);
                flag = !flag;
            }
        }

        bool flag1 = true;//判断标志位
        /// <summary>
        /// 强制输出拓展模块点
        /// </summary>
        public void OutputEx(short mdlNo, short DoIndex)
        {
            if (flag1 == false)//判断标志位
            {
                mc.GT_SetExtIoBit(0, mdlNo, DoIndex, 0);
                flag1 = !flag1;
            }
            else if (flag1 == true)
            {
                mc.GT_SetExtIoBit(0, mdlNo, DoIndex, 1);
                flag1 = !flag1;
            }
        }

        public class Alarm
        {
            //声明自定义事件委托
            public delegate void AlarmEnventHandler(object sender, EventArgs e);
            //public delegate void AlarmEnventHandler();
            //声明自定义事件
            public event AlarmEnventHandler AlarmEvent;
            //触发事件方法
            public void OnAlarm()
            {
                if (this.AlarmEvent != null)
                {
                    this.AlarmEvent(this,new EventArgs());
                }   
            }
        }
    }
}
